package com.wolfking.converter.transform.extend;

import com.google.common.collect.Lists;
import com.google.gson.*;
import com.wolfking.converter.transform.AbstractExtendTransform;
import com.wolfking.converter.util.CaesarUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
public class JsonExtractMoreFirstTransform extends AbstractExtendTransform<Object> {


    private Config config;


    public JsonExtractMoreFirstTransform() {
    }

    public JsonExtractMoreFirstTransform(String format) {
        config = new Gson().fromJson(format, Config.class);
    }

    @Override
    public String transform(Object value) {
        if (Objects.isNull(value)) {
            if (StringUtils.isNotBlank(config.getDefaultValue())) {
                return config.getDefaultValue();
            } else {
                return "";
            }
        }
        String beforeValue;
        if (value instanceof String) {
            beforeValue = value.toString();
        } else if (value instanceof byte[]) {
            beforeValue = new String((byte[]) value, StandardCharsets.UTF_8);
        } else {
            beforeValue = value.toString();
        }

        if (CaesarUtil.isEncrypted(beforeValue)) {
            beforeValue = CaesarUtil.decode(beforeValue);
        }

        try {
            JsonElement element = JsonParser.parseString(beforeValue);
            if (!element.isJsonArray() && !element.isJsonObject()) {
                if (config.isReturnOrigin()) {
                    return beforeValue;
                } else if (StringUtils.isNotBlank(config.getDefaultValue())) {
                    return config.getDefaultValue();
                } else {
                    return "";
                }
            }
            for (String path : config.getPaths()) {
                List<String> maskString = extractString(element, path);
                maskString = maskString.stream().filter(StringUtils::isNotBlank).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(maskString)) {
                    return String.join(",", maskString);
                }
            }
            if (config.isReturnOrigin()) {
                return beforeValue;
            } else if (StringUtils.isNotBlank(config.getDefaultValue())) {
                return config.getDefaultValue();
            }
            return "";
        } catch (Exception e) {
            log.warn("", e);
            if (config.isReturnOrigin()) {
                return beforeValue;
            } else if (StringUtils.isNotBlank(config.getDefaultValue())) {
                return config.getDefaultValue();
            } else {
                return "";
            }
        }
    }

    public static List<String> extractString(JsonElement element, String path) {
        List<String> overall = Lists.newArrayList();
        try {

            if (element.isJsonObject()) {
                JsonObject object = element.getAsJsonObject();
                extractElement(object, path, overall);
            } else if (element.isJsonArray()) {
                JsonArray array = element.getAsJsonArray();
                for (JsonElement ele : array) {
                    extractElement(ele.getAsJsonObject(), path, overall);
                }
            }
        } catch (Throwable e) {
            log.error("mask error", e);
        }
        return overall;
    }

    private static void extractElement(JsonElement element, String path, Collection<String> overall) {
        if (element != null) {
            String[] paths = path.split("\\.");
            if (paths.length == 1) {
                if (element.isJsonObject()) {
                    JsonObject asJsonObject = element.getAsJsonObject();
                    JsonElement asJsonElement = asJsonObject.get(path);
                    if (asJsonElement == null || asJsonElement.isJsonNull()) {
                        return;
                    }
                    JsonPrimitive primitive = asJsonObject.getAsJsonPrimitive(path);
                    if (primitive != null) {
                        String asString = primitive.getAsString();
                        if (StringUtils.isNotBlank(asString)) {
                            overall.add(asString);
                        }
                    }
                } else if (element.isJsonArray()) {
                    JsonArray array = element.getAsJsonArray();
                    for (JsonElement ele : array) {
                        extractElement(ele.getAsJsonObject(), path, overall);
                    }
                }
            } else {
                Optional<String> reduce = Stream.of(paths).skip(1).reduce((e1, e2) -> (e1 + "." + e2));
                if (reduce.isPresent()) {
                    if (element.isJsonObject()) {
                        JsonObject asJsonObject = element.getAsJsonObject();
                        extractElement(asJsonObject.get(paths[0]), reduce.get(), overall);
                    } else if (element.isJsonArray()) {
                        JsonArray asJsonArray = element.getAsJsonArray();
                        for (JsonElement jsonElement : asJsonArray) {
                            extractElement(jsonElement.getAsJsonObject().get(paths[0]), reduce.get(), overall);
                        }
                    }
                }
            }
        }
    }


    @Data
    private static class Config {
        private boolean returnOrigin = false;
        private String defaultValue = "";
        private List<String> paths;
    }


    @Override
    public String getExampleConfig() {
        return "{\n" +
                "\t\"returnOrigin\": false,\n" +
                "\t\"defaultValue\": \"\",\n" +
                "\t\"paths\": [\n" +
                "\t\t\"a\",\n" +
                "\t\t\"b\"\n" +
                "\t]\n" +
                "}";
    }

    @Override
    public String getExampleConfigDesc() {
        return "{\n" +
                "\t\"returnOrigin\": 没匹配到返回源数据,false返回空字符串\n" +
                "\t\"defaultValue\": \"默认值\",\n" +
                "\t\"paths\": [\n" +
                "\t\t\"路径a\",\n" +
                "\t\t\"路径b\"\n" +
                "\t]\n" +
                "}";
    }
}
